//
//  config_impl.hpp
//  utilities
//
//  Created by Sam Jaffe on 2/4/15.
//  Copyright (c) 2015 Sam Jaffe. All rights reserved.
//

#pragma once

#include <sys/ioctl.h>
#include <unistd.h>
#include <vector>
#include <iomanip>
#include <algorithm>

namespace options {
    
    config::config() {
#       ifdef TIOCGSIZE
        struct ttysize ts;
        ioctl(STDIN_FILENO, TIOCGSIZE, &ts);
        cols = std::max(cols, ts.ts_cols);
        lines = ts.ts_lines;
#       elif defined(TIOCGWINSZ)
        struct winsize ts;
        ioctl(STDIN_FILENO, TIOCGWINSZ, &ts);
        cols = std::max(cols, ts.ws_col);
        lines = ts.ws_row;
#       endif /* TIOCGSIZE */
    }
    
    config::~config() {
        for (auto p : parsers) {
            delete p;
        }
    }
    
    void config::print_options() const {
        std::cout << "Options:\n";
        const std::size_t desc_width = static_cast<std::size_t>(0.7 * cols);
        for (auto& pair : usage_info) {
            std::stringstream ss;
            ss << pair.second.name;
            if (pair.second.name.back() != '=') ss << " ";
            if (!pair.second.argument_types.empty()) {
                ss << "<";
                auto it = pair.second.argument_types.begin();
                ss << *it++;
                for (; it != pair.second.argument_types.end(); ++it) {
                    ss << " " << *it;
                }
                ss << ">";
            }
            std::cout << ss.str() << std::setw(cols - desc_width - ss.str().size()) << " : ";
            const std::size_t size = pair.second.desc.size();
            std::size_t idx = 0;
            while (idx < size) {
                if (idx) std::cout << std::setw(cols - desc_width) << " ";
                std::size_t step = std::min(desc_width, size - idx);
                if (step == desc_width && step != (size - idx) && pair.second.desc[idx + step - 1] != ' ') {
                    --step;
                    std::cout << pair.second.desc.substr(idx, idx + step);
                    if (pair.second.desc[idx + step - 1] != ' ') {
                        std::cout << "-";
                    }
                    std::cout << "\n";
                } else {
                    std::cout << pair.second.desc.substr(idx, idx + step) << "\n";
                }
                idx += step;
            }
        }
    }
    
    typename config::options_map::iterator config::find_option(const std::string& key) {
        return parameter_mapping.find(key);
    }
    
    typename config::options_map::iterator config::no_option() {
        return parameter_mapping.end();
    }
    
    description::description(const std::string &name, const std::vector<std::string> &types, const std::string& desc) : name(name), argument_types(types), desc(desc) {
        
    }
    
}
